﻿using System;
using System.Text.RegularExpressions;
using System.Text;
using System.Web;
using System.IO;
using System.Configuration;
using Eagle.Config;

namespace Eagle.Common
{
    /// <summary>
    /// 常用工具类
    /// </summary>
    public class EagleUtils
    {
        #region 私有成员
        private static readonly object locker = new object();
        #endregion

        #region 判断对象是否为空或NULL
        /// <summary>
        /// 判断对象是否为空或NULL,如果是空或NULL返回true，否则返回false
        /// </summary>
        /// <param name="value">要检测的字符串</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(object value)
        {
            if (value == null)
                return true;
            return (value.ToString().Trim(' ').Length == 0);
        }
        #endregion

        #region 截取字符枚举值
        /// <summary>
        /// 截取字符枚举值,Varchar--英文一个字节，中文两个字节，NVarchar--无论中英文都是两个字节
        /// </summary>
        public enum CutType
        {
            /// <summary>
            /// Varchar--英文一个字节，中文两个字节
            /// </summary>
            Varchar,
            /// <summary>
            /// NVarchar--无论中英文都是两个字节
            /// </summary>
            NVarchar
        }
        #endregion

        #region 获取指定长度的字符串
        /// <summary>
        /// 获取指定长度的字符串
        /// </summary>
        /// <param name="value">输入的字符串</param>
        /// <param name="count">限定长度，按字节数算</param>
        /// <param name="ellipsis">是否需要省略号,true--需要，false--不需要</param>
        /// <param name="cuttype">截取类型</param>
        /// <returns>截取后的字符串，如果是NVarchar--则20个字节就会有10个字符，Varchar--20个字节会有>=10个字符</returns>
        public static string CutString(string value, int length, bool ellipsis, CutType cuttype)
        {
            value = value.Trim();
            if (value.Length == 0)
                return string.Empty;
            if (cuttype == CutType.NVarchar)
            {
                if (value.Length > length / 2)
                {
                    value = value.Substring(0, length / 2);
                    if (ellipsis)
                        return value + "..";
                }
            }
            else
            {
                int len = value.Length;
                int i = 0;
                for (; i < length && i < len; ++i)
                {
                    if ((int)(value[i]) > 0xFF)
                        --length;
                }
                if (length < i && i > 0)
                    length = i - 1;
                else if (length > len)
                    length = len;
                if (ellipsis&&length<len)
                    return value.Substring(0, length) + "..";
                return value.Substring(0, length);
            }
            return value;
        }
        #endregion

        #region 按一定格式拼接字符串组中的字符串
        /// <summary>
        /// 按一定格式拼接字符串组中的字符串
        /// </summary>
        /// <param name="separator">字符串间分隔符</param>
        /// <param name="identifier">每个字符串所需的标识符，例如'kkk','lll'</param>
        /// <param name="value">要拼接的字符串组</param>
        /// <returns></returns>
        public static string Join(string separator, string identifier, string[] value)
        {
            int valueLength = value.Length;
            StringBuilder text = new StringBuilder(valueLength * 20);
            foreach (string v in value)
            {
                text.Append(identifier + v + identifier + separator);
            }
            int textLength = text.Length;
            int separatorLength = separator.Length;
            if (textLength > 0)
                text.Remove(textLength - separatorLength, separatorLength);
            return text.ToString();
        }
        /// <summary>
        /// 按一定格式拼接字符串组中的字符串
        /// </summary>
        /// <param name="separator">字符串间分隔符</param>
        /// <param name="identifier">每个字符串所需的标识符，例如'kkk','lll'</param>
        /// <param name="value">要拼接的字符串组</param>
        /// <returns></returns>
        public static string Join(string separator, string identifier, int[] value)
        {
            int valueLength = value.Length;
            StringBuilder text = new StringBuilder(valueLength * 20);
            foreach (int v in value)
            {
                text.Append(identifier + v + identifier + separator);
            }
            int textLength = text.Length;
            int separatorLength = separator.Length;
            if (textLength > 0)
                text.Remove(textLength - separatorLength, separatorLength);
            return text.ToString();
        }
        #endregion

        //#region 字符过滤编码函数及解码函数
        ///// <summary>
        ///// 字符转义函数
        ///// </summary>
        ///// <param name="value">输入字符串</param>
        ///// <returns></returns>
        //public static string HtmlEncode(string value)
        //{
        //    if (string.IsNullOrEmpty(value))
        //        return string.Empty;
        //    value = value.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "&quot;").Replace("'", "&apos;").Replace(" ", "&nbsp;");
        //    return value;
        //}
        ///// <summary>
        ///// 字符转义函数
        ///// </summary>
        ///// <param name="value">传入字符串</param>
        ///// <returns></returns>
        //public static string HtmlDecode(string value)
        //{
        //    if (string.IsNullOrEmpty(value))
        //        return string.Empty;
        //    value = value.Replace("&lt;", "<").Replace("&gt;", ">").Replace("&quot;", "\"").Replace("&apos;", "'").Replace("&nbsp;", " ").Replace("&amp;", "&");
        //    return value;
        //}
        //#endregion

        #region 内容过滤编码函数

        /// <summary>
        /// 转义html，你也可以自己增加要替换的标签
        /// </summary>
        /// <param name="value">输入字符串</param>
        /// <returns></returns>
        public static string RichTextEncode(string value)
        {
            if (string.IsNullOrEmpty(value))
                return string.Empty;
            //value = value.Replace(((char)38).ToString(), "&amp;");//&
            value = Regex.Replace(value, "<a href=", "<a target=_blank href=", RegexOptions.Compiled | RegexOptions.IgnoreCase);
            value = Regex.Replace(value, @"<(.[^>]*)(onerror|onload|onmouseover|onclick|ondblclick|onmouseout|javascript:)", "&lt;$1$2;", RegexOptions.Compiled | RegexOptions.IgnoreCase);
            value = Regex.Replace(value, @"<(\/|)(link|script|object|iframe|frameset|form|caption|behavior|!--|meta|style)", "&lt;$1$2", RegexOptions.Compiled | RegexOptions.IgnoreCase);
            return value;
        }

        #endregion

        #region 格式化要显示的内容，主要用于在网页上显示由textarea产生的内容
        /// <summary>
        /// 格式化要显示的内容，主要用于在网页上显示由textarea产生的内容
        /// </summary>
        /// <param name="value">传入字符串</param>
        /// <param name="type">转换类型</param>
        /// <returns></returns>
        public static string FormatHtml(string value, FormatType type)
        {
            if (value.Trim().Length == 0)
                return string.Empty;
            if (type==FormatType.Br)
            {
                value = value.Replace("\n", "<br/>");
            }
            else
            {
                value = "<p>"+value.Replace("\n", "</p><p>")+"</p>";
            }
            return value;
        }
        #endregion

        #region 升级15位身份证到18位
        /// <summary>
        /// 升级15位身份证到18位
        /// </summary>
        /// <param name="value">15位身份证号码</param>
        /// <returns></returns>
        public static string UpIdentityCard15To18(string value)
        {
            if (value == null)
                return "";
            string myvalue = value.Trim();
            if (myvalue.Length != 15)
                return "";
            myvalue = myvalue.Insert(6, "19");
            int[] checkValue = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                sum += int.Parse(myvalue[i].ToString()) * checkValue[i];
            }
            //效验码的结果对照
            string[] checkResult = new string[] { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };
            //可能的余数
            int[] modResult = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            int mod = sum % 11;
            string checkCode = string.Empty;
            for (int i = 0; i < 11; i++)
            {
                if (mod == modResult[i])
                {
                    checkCode = checkResult[i];
                    break;
                }
            }
            return myvalue + checkCode;
        }
        #endregion

        #region 验证身份证号码
        /// <summary>
        /// 验证身份证号码
        /// </summary>
        /// <param name="value">18位身份证号码</param>
        /// <returns></returns>
        public static bool CheckIdentityCard(string value)
        {
            //身份证的加权因子从第一位开始
            //7   9 10   5   8   4   2   1   6   3   7   9 10   5   8   4   2
            if (value == null)
                return false;
            string myvalue = value.Trim();
            if (!(myvalue.Length == 18 || myvalue.Length == 15))
                return false;
            myvalue = Regex.Match(myvalue, @"^[0-9Xx]+$").Value;
            if (myvalue.Length == 15)
                myvalue = myvalue.Insert(5, "19");
            int[] checkValue = new int[] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                sum += int.Parse(myvalue[i].ToString()) * checkValue[i];
            }
            //效验码的结果对照
            string[] checkResult = new string[] { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };
            //可能的余数
            int[] modResult = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            int mod = sum % 11;
            string checkCode = string.Empty;
            for (int i = 0; i < 11; i++)
            {
                if (mod == modResult[i])
                {
                    checkCode = checkResult[i];
                    break;
                }
            }
            string lastChar = myvalue.Substring(17).ToUpper();
            if (checkCode != lastChar)
                return false;
            return true;
        }
        #endregion

        #region 获得当前页面客户端的IP
        /// <summary>
        /// 获得当前页面客户端的IP
        /// </summary>
        /// <returns>当前页面客户端的IP</returns>
        public static string GetClientIP()
        {
            string result = String.Empty;
            result = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
            if (EagleUtils.IsNullOrEmpty(result))
            {
                result = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            }

            if (EagleUtils.IsNullOrEmpty(result))
            {
                result = HttpContext.Current.Request.UserHostAddress;
            }

            if (EagleUtils.IsNullOrEmpty(result) || !IsIP(result))
            {
                return "0.0.0.0";
            }
            return result;
        }
        /// <summary>
        /// 是否为ip
        /// </summary>
        /// <param name="ip">要验证的IP</param>
        /// <returns></returns>
        public static bool IsIP(string ip)
        {
            return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
        }
        #endregion

        #region 判断当前访问是否来自指定浏览器软件
        /// <summary>
        /// 判断当前访问是否来自指定浏览器软件
        /// </summary>
        public static bool IsBrowser()
        {
            string[] BrowserName = { "ie", "opera", "netscape", "mozilla", "desktop", "firefox" };
            string curBrowser = HttpContext.Current.Request.Browser.Type.ToLower();
            for (int i = 0; i < BrowserName.Length; i++)
            {
                if (curBrowser.IndexOf(BrowserName[i]) >= 0)
                {
                    return true;
                }
            }
            return false;
        }
        #endregion

        #region 生成随机数方法
        /// <summary>
        /// 生成随机数方法
        /// </summary>
        /// <param name="count">随机数的最大位数</param>
        /// <returns></returns>
        public static int CreateRandom(byte length)
        {
            string rndNumber = "1";
            rndNumber = rndNumber.PadRight(length + 1, '0');
            Random rnd = new Random();
            return rnd.Next(1, int.Parse(rndNumber));
        }
        #endregion

        #region 转换相对路径为物理路径
        /// <summary>
        /// 转换相对路径为物理路径
        /// </summary>
        /// <param name="path">如果是文件或目录的根路径，则前面必须有"/"，如：/xml/myxml.config或/xml/，否则都是相对当前网页的物理路径</param>
        /// <returns></returns>
        public static string ConvertToPhysicalPath(string path)
        {
            int length = path.Length;
            if (length >= 2)
            {
                if (path[1] == ':')
                    return path;
                else
                    if (path[0] == '\\' && path[1] == '\\')
                        return path;
            }

            if (HttpContext.Current != null)
            {
                return HttpContext.Current.Server.MapPath(path);
            }
            else //非web程序引用       
            {
                path = path.Replace("/", "\\");
                path = path.Replace("~", "");
                if (path.StartsWith("\\"))
                {
                    path = path.TrimStart('\\');
                }
                return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
            }
        }
        #endregion

        #region 在文本文件中记录程序的错误日志
        /// <summary>
        /// 在文本文件中记录程序的错误日志
        /// </summary>
        /// <param name="error">错误信息</param>
        public static void WriteErrorToTxt(string error)
        {
            string fileName = EagleUtils.ConvertToPhysicalPath("~/Log/ErrorLog/" + DateTime.Now.ToString("yyyy-MM-dd")) + "/" + DateTime.Now.Hour.ToString() + ".txt";
            WriteErrorToTxt(fileName, error);
        }
        /// <summary>
        /// 在文本文件中记录程序的错误日志
        /// </summary>
        /// <param name="fileName">要记录的文件物理路径</param>
        /// <param name="error">错误信息</param>
        public static void WriteErrorToTxt(string fileName, string error)
        {
            string msg = string.Empty;
            try
            {
                lock (locker)
                {
                    string directoryPath = Path.GetDirectoryName(fileName);
                    if (!Directory.Exists(directoryPath))
                        Directory.CreateDirectory(directoryPath);
                    using (StreamWriter sw = new StreamWriter(fileName, true, Encoding.UTF8))
                    {
                        string url = string.Empty;
                        if (HttpContext.Current != null)
                            url = HttpContext.Current.Request.Url.ToString();
                        sw.WriteLine("来源：" + url + "\r\n时间：" + DateTime.Now.ToString() + "\r\n错误信息：" + error + "\r\n");
                    }
                }
            }
            catch
            {
                msg = "网站根路径下需要有Log文件夹，且需要给予写权限";
            }
            if (msg.Length > 0)
            {
                if (HttpContext.Current != null)
                {
                    HttpContext.Current.Response.Clear();
                    HttpContext.Current.Response.Write("<script language=\"javascript\" type=\"text/javascript\">alert('" + msg + "')</script>");
                    HttpContext.Current.Response.End();
                }
            }
        }
        #endregion

        #region 返回当前网站的根路径
        private static string _WebRoot;
        /// <summary>
        /// 返回当前网站的根路径,如：http://www.mydaigo.com
        /// </summary>
        /// <returns>返回当前网站的根路径</returns>
        public static string WebRoot
        {
            get
            {
                if (_WebRoot == null)
                {
                    string root = "", port = "", host = "";
                    root = HttpContext.Current.Request.ApplicationPath;
                    port = HttpContext.Current.Request.Url.Port.ToString();
                    host = HttpContext.Current.Request.Url.Host;
                    if (root.Equals("/"))
                        root = "";
                    if (port.Equals("80"))
                    { port = ""; }
                    else
                    { port = ":" + port; }
                    _WebRoot = "http://" + host + port + root;
                    return _WebRoot;
                }
                return _WebRoot;
            }
        }
        #endregion

        #region 在服务器上创建文件夹
        /// <summary>
        /// 在服务器上创建文件夹
        /// </summary>
        /// <param name="path">文件或文件夹的物理路径</param>
        public static void CreateDirectory(string path)
        {
            int position = 0;
            string directory = path;
            position = path.LastIndexOf('\\');//准备在web服务器上创建文件夹
            lock (locker)
            {
                if (position > 0 && !path.EndsWith("\\"))
                {
                    directory = path.Substring(0, position);
                }
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);//web服务器不存在该文件夹就创建
                }
            }
        }
        #endregion

        #region 在服务器上创建文件
        /// <summary>
        /// 在服务器上创建文件
        /// </summary>
        /// <param name="fileName">创物理路径</param>
        /// <returns></returns>
        public static void CreateLocalFile(string fileName)
        {
            lock (locker)
            {
                if (!File.Exists(fileName))
                {
                    string directoryPath = Path.GetDirectoryName(fileName);
                    if (!Directory.Exists(directoryPath))
                        Directory.CreateDirectory(directoryPath);
                    using (FileStream fs = File.Create(fileName)) { }
                    //FileStream fs = new FileStream(HttpContext.Current.Request.MapPath(path), FileMode.Create,FileAccess.ReadWrite);
                }
                File.SetAttributes(fileName, FileAttributes.Archive);
            }
        }
        #endregion

        #region 数字转换为人民币大写
        /// <summary>
        /// 数字转换为人民币大写
        /// </summary>
        private static string[] cstr = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
        private static string[] wstr = { "", "", "拾", "佰", "仟", "萬", "拾", "佰", "仟", "億", "拾", "佰", "仟" };
        private static string[] xstr = { "角", "分" };
        /// <summary>
        /// 数字转换为人民币大写
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ConvertToRmb(string value)
        {
            bool flag = false;
            if (!Regex.IsMatch(value, @"^-?\d{0,11}.?\d{0,2}$", RegexOptions.IgnoreCase))
            {
                return string.Empty;
            }
            if (value.StartsWith("-"))
            {
                flag = true;
                value = value.Substring(1);
            }
            int leftLength = 0, rightLength = 0, strLength = 0, i = 0;
            strLength = value.Length;
            leftLength = value.IndexOf('.');
            string tmpstr = string.Empty, rstr = string.Empty, leftStr = string.Empty, rightStr = string.Empty;
            if (leftLength > 0)
            {
                rightLength = strLength - leftLength - 1;
                leftStr = value.Substring(0, leftLength);
                rightStr = value.Substring(leftLength + 1, rightLength);
                for (i = 1; i <= leftLength; i++)
                {
                    tmpstr = leftStr.Substring(leftLength - i, 1);
                    rstr = string.Concat(cstr[Int32.Parse(tmpstr)] + wstr[i], rstr);
                }
                rstr = rstr + "圆";
                if (rightLength > 0)
                {
                    for (i = 0; i < rightLength; i++)
                    {
                        tmpstr = rightStr.Substring(i, 1);
                        rstr = string.Concat(rstr, cstr[Int32.Parse(tmpstr)] + xstr[i]);
                    }
                }
            }
            else
            {
                leftStr = value;
                leftLength = value.Length;
                for (i = 1; i <= leftLength; i++)
                {
                    tmpstr = leftStr.Substring(leftLength - i, 1);
                    rstr = string.Concat(cstr[Int32.Parse(tmpstr)] + wstr[i], rstr);
                }
            }
            rstr = rstr.Replace("拾零", "拾");
            rstr = rstr.Replace("零拾", "零");
            rstr = rstr.Replace("零佰", "零");
            rstr = rstr.Replace("零仟", "零");
            rstr = rstr.Replace("零萬", "萬");
            for (i = 1; i <= 6; i++)
                rstr = rstr.Replace("零零", "零");
            rstr = rstr.Replace("零萬", "零");
            rstr = rstr.Replace("零億", "億");
            rstr = rstr.Replace("零零", "零");
            rstr += "整";
            if (flag)
                rstr = "负" + rstr;
            return rstr;
        }

        #endregion

        #region 获取webconfig配置项键值
        /// <summary>
        /// 获取网站配置ConfigurationManager_AppSettings键值
        /// </summary>
        /// <param name="configKeyName">AppSettings_keyName</param>
        /// <returns>AppSettings_keyValue</returns>
        public static string GetConfigAppSettings(string configKeyName)
        {
            try
            {
                if (configKeyName != null)
                    return ConfigurationManager.AppSettings[configKeyName];
                return string.Empty;
            }
            catch (Exception ex)
            {
                EagleUtils.WriteErrorToTxt(ex.ToString());
                return string.Empty;
            }
        }
        #endregion

        #region 统一网站编码
        /// <summary>
        /// 字符串编码
        /// </summary>
        /// <param name="value">输入值</param>
        /// <returns></returns>
        public static string UrlEncode(string value)
        {
            if (string.Compare(EagleSettings.Instance.Encoding, "utf-8", StringComparison.CurrentCultureIgnoreCase) == 0)
                return HttpUtility.UrlEncode(value, Encoding.UTF8);
            return HttpUtility.UrlEncode(value, Encoding.GetEncoding("gbk"));
        }
        /// <summary>
        /// 字符串解码
        /// </summary>
        /// <param name="value">输入值</param>
        /// <returns></returns>
        public static string UrlDecode(string value)
        {
            if (string.Compare(EagleSettings.Instance.Encoding, "utf-8", StringComparison.CurrentCultureIgnoreCase) == 0)
                return HttpUtility.UrlDecode(value, Encoding.UTF8);
            return HttpUtility.UrlDecode(value, Encoding.GetEncoding("gbk"));
        }
        #endregion

        #region Base64编码解码
        /// <summary>
        /// Base64编码
        /// </summary>
        /// <param name="value">要编码的字符串</param>
        /// <returns></returns>
        public static string ToBase64String(string value)
        {
            if (value.Length > 0)
            {
                byte[] inputbyte = Encoding.UTF8.GetBytes(value);
                return Convert.ToBase64String(inputbyte).Replace('+', '@').Replace('/', '*');
            }
            return string.Empty;
        }
        /// <summary>
        /// Base64解码
        /// </summary>
        /// <param name="value">要解码的字符串</param>
        /// <returns></returns>
        public static string FromBase64String(string value)
        {
            if (value.Length > 0)
            {
                byte[] inputbyte = Convert.FromBase64String(value.Replace('@', '+').Replace('*', '/'));
                return Encoding.UTF8.GetString(inputbyte);
            }
            return string.Empty;
        }
        #endregion

        #region Web下载文件
        /// <summary>
        /// Web下载文件
        /// </summary>
        /// <param name="physicalPath">要下载文件的物理路径</param>
        /// <param name="contentType">文件类型，如 excel是 application/vnd.ms-excel word 是application/msword</param>
        public static void DownloadFile(string physicalPath, string contentType)
        {
            HttpContext.Current.Response.Clear();

            // Buffer to read 10K bytes in chunk:
            byte[] buffer = new Byte[10000];

            // Length of the file:
            int length;

            // Total bytes to read:
            long dataToRead;

            string filename = Path.GetFileName(physicalPath);
            using (Stream iStream = new FileStream(physicalPath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                // Total bytes to read:
                dataToRead = iStream.Length;
                HttpContext.Current.Response.ContentEncoding = Encoding.UTF8;
                HttpContext.Current.Response.ContentType = contentType;
                HttpContext.Current.Response.AddHeader("Content-Length", iStream.Length.ToString());
                HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, Encoding.UTF8));

                // Read the bytes.
                while (dataToRead > 0)
                {
                    // Verify that the client is connected.
                    if (HttpContext.Current.Response.IsClientConnected)
                    {
                        // Read the data in buffer.
                        length = iStream.Read(buffer, 0, 10000);

                        // Write the data to the current output stream.
                        HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);

                        // Flush the data to the HTML output.
                        HttpContext.Current.Response.Flush();
                        buffer = new Byte[10000];
                        dataToRead = dataToRead - length;
                    }
                    else
                    {
                        //prevent infinite loop if user disconnects
                        dataToRead = -1;
                    }
                }
            }
        }
        #endregion

        #region 枚举
        /// <summary>
        /// 格式化TextArea产生的内容
        /// </summary>
        public enum FormatType
        {
            /// <summary>
            /// 把换行符转为Br标签
            /// </summary>
            Br = 0,
            /// <summary>
            /// 把换行符转为P标签
            /// </summary>
            P = 1
        }
        #endregion
    }
}
